/** @file
  Secondary System Description Table (SSDT) for hardware reduced events.

  Arm Reference Design platforms implement the HW-Reduced ACPI model and do not
  support legacy ACPI Fixed Hardware interfaces.

  GPIO Signalled ACPI event is one of the methods for signalling events in
  HW-Reduced ACPI model. In this method, ACPI events can be signaled when a GPIO
  Interrupt is received by OSPM and that GPIO Interrupt Connection is listed in
  a GPIO controller device’s _AEI object.

  Interrupt Signalled ACPI event is another method of signalling events in
  HW-Reduced ACPI model. In this method, ACPI event is generated when an
  interrupt is received by the OSPM which is listed in the Generic Event Device
  (GED) _CRS object.

  Copyright (c) 2021, ARM Limited. All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent

  @par Specification Reference:
    - ACPI 6.4, Chapter 5.6.5, GPIO-signaled ACPI Events
    - Arm Base Boot Requirements 1.0, Issue F, Chapter 8.5.3, GPIO controllers
    - ACPI 6.4, Chapter 5.6.9, Interrupt-signaled ACPI events
    - Arm Base Boot Requirements 1.0, Issue F, Chapter 8.5.4 Generic Event
      Devices
**/

#include "SgiAcpiHeader.h"

DefinitionBlock("SsdtEvent.aml", "SSDT", 2, "ARMLTD", "ARMSGI", EFI_ACPI_ARM_OEM_REVISION) {
  /* GPIO Controller 0 device. Use _AEI object to configure pin 0 for
     signalling HW-Reduced events and the _L00 method to handle the event
     generated by pin 0.
  */
  Device (\_SB.GPI0)
  {
    Name (_HID, "ARMH0061")     /* PrimeCell GPIO */
    Name (_UID, 0)

    /* Resource setting for GPIO controller 0 */
    Name (_CRS, ResourceTemplate () {
      Memory32Fixed (
        ReadWrite,
        FixedPcdGet32 (PcdGpioController0BaseAddress),
        FixedPcdGet32 (PcdGpioController0Size)
      )
      Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
        FixedPcdGet32 (PcdGpioController0Interrupt)
      }
    })

    /* ACPI Event information for GPIO controller 0 */
    Name (_AEI, ResourceTemplate() {
      GpioInt (Level, ActiveHigh, Exclusive, PullDown, , "\\_SB.GPI0") {0}
    })

    /* Event handler for pin0 */
    Method (_L00) {
      Printf ("GPIO0 Pin0 Toggled")
      Store (1, INC0)
    }

    /* Mapping for interrupt clear register */
    OperationRegion (
      GIO0,
      SystemMemory,
      FixedPcdGet32 (PcdGpioController0BaseAddress),
      FixedPcdGet32 (PcdGpioController0Size)
    )
    Field (GIO0, ByteAcc, NoLock, Preserve) {
      Offset (0x41C),    /* WO Intr clear on writing 1 to resp bit */
      INC0, 8
    }
  }

  /* ACPI GED object Template. Arm's reference design platforms include a SP804
     dual timer which is implemented as part of the RoS sub-system. The SP804
     interrupt is used in GED as interrupt source. */
  Device (\_SB.GED0) {
    Name (_HID, "ACPI0013")
    Name (_UID, 0)

    /* Resource setting for GED */
    Name (_CRS, ResourceTemplate () {
      Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) {
        FixedPcdGet32 (PcdSp804DualTimerInterrupt)
      }
    })

    Method (_STA, 0x0, NotSerialized) {
      return (0xF);
    }

    /* Register map for interrupt clear register */
    OperationRegion (
      DTIM,
      SystemMemory,
      FixedPcdGet32 (PcdSp804DualTimerBaseAddress),
      FixedPcdGet32 (PcdSp804DualTimerSize))
    Field (DTIM, DWordAcc, NoLock, Preserve) {
      Offset (0x0C),
      T1IC, 32,       /* 0x0C Timer 1 Interrupt clear */
    }

    /* GED event handler */
    Method (_EVT, 1, Serialized) {
      switch (ToInteger (Arg0))
      {
        case (FixedPcdGet32 (PcdSp804DualTimerInterrupt)) {
          Store (0x01, T1IC)
        }
      }
    }
  } /* Device (\_SB.GED0) */

}
